﻿Imports OpenTK
Imports OpenTK.Graphics
Imports OpenTK.Graphics.OpenGL4

Public Class DefferedRendering
    Public fbo As Integer

    Dim rboDepth As Integer
    Public texPosition As Integer
    Public texNormal As Integer
    Public texUVID As Integer
    Public texPresent As Integer

    Public triangleCount As Integer
    Public Sub New(width As Integer, height As Integer, triangles As Integer)
        triangleCount = triangles

        fbo = GL.GenFramebuffer()

        rboDepth = GL.GenRenderbuffer()
        texPosition = GL.GenTexture()
        texNormal = GL.GenTexture()
        texUVID = GL.GenTexture()
        texPresent = GL.GenTexture()

        GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, rboDepth)
        GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent, width, height)

        GL.BindTexture(TextureTarget.Texture2D, texPosition)
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, width, height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureMagFilter.Nearest)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureMinFilter.Nearest)

        GL.BindTexture(TextureTarget.Texture2D, texNormal)
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, width, height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureMagFilter.Nearest)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureMinFilter.Nearest)

        GL.BindTexture(TextureTarget.Texture2D, texUVID)
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, width, height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureMagFilter.Nearest)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureMinFilter.Nearest)

        GL.BindTexture(TextureTarget.Texture2D, texPresent)
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, width, height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureMagFilter.Nearest)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureMinFilter.Nearest)

        ibo = GL.GenBuffer()
        Dim indices(triangleCount * 3 - 1) As UShort
        For i = 0 To triangleCount - 1
            indices(i * 3 + 0) = i
            indices(i * 3 + 1) = i + triangleCount
            indices(i * 3 + 2) = i + triangleCount * 2
        Next
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo)
        GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * 2, indices, BufferUsageHint.StaticDraw)
    End Sub

    Public ibo As Integer

    Public Sub SetupUniform(model As Matrix4, view As Matrix4, projection As Matrix4)
        Dim program = ShaderManager.Active("GBuffer")

        Dim uModel As Integer = GL.GetUniformLocation(program, "Model")
        GL.UniformMatrix4(uModel, False, Matrix4.Identity)

        Dim uMVP As Integer = GL.GetUniformLocation(program, "MVP")
        GL.UniformMatrix4(uMVP, False, Matrix4.Identity * view * projection)

        RayTracing.sceneManager.SetupTextureHandle(program)
    End Sub

    Public Sub DrawTransformFeedBackTriangle(bufferOutput As Integer)

        Dim stride As Integer = triangleCount * 3 * 4 * 4
        GL.BindBuffer(BufferTarget.ArrayBuffer, bufferOutput)

        GL.EnableVertexAttribArray(0)
        GL.VertexAttribPointer(0, 4, VertexAttribPointerType.Float, False, 0, 0)

        GL.EnableVertexAttribArray(1)
        GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, False, 0, stride)

        GL.EnableVertexAttribArray(2)
        GL.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, False, 0, stride * 2)

        'GL.DrawArrays(PrimitiveType.Triangles, 0, triangleCount * 3)
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo)
        GL.DrawElements(PrimitiveType.Triangles, triangleCount * 3, DrawElementsType.UnsignedShort, IntPtr.Zero)

        'Dim q = GL.GenQuery()
        'Dim result As Integer
        'GL.BeginQuery(QueryTarget.PrimitivesGenerated, q)
        'GL.EndQuery(QueryTarget.PrimitivesGenerated)
        'GL.GetQueryObject(q, GetQueryObjectParam.QueryResult, result)
        'GL.DeleteQuery(q)
        'result = 0

    End Sub

    Public Sub BeginDraw()
        Dim program = ShaderManager.Active("GBuffer")
        '在shader里指定location不用管下面的BindFragDataLocation
        GL.BindFragDataLocation(program, 0, "fragColor")
        GL.BindFragDataLocation(program, 1, "fragPosition")
        GL.BindFragDataLocation(program, 2, "fragNormal")
        GL.BindFragDataLocation(program, 3, "fragCoordID")

        GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo)
        GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, texPresent, 0)
        GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment1, TextureTarget.Texture2D, texPosition, 0)
        GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment2, TextureTarget.Texture2D, texNormal, 0)
        GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment3, TextureTarget.Texture2D, texUVID, 0)

        GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, rboDepth)
        Dim status As FramebufferErrorCode = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer)
        If status <> FramebufferErrorCode.FramebufferComplete Then
            Throw New Exception("FBO Error:" + status.ToString())
        End If

        Dim drawbuffers() As DrawBuffersEnum = {
            DrawBuffersEnum.ColorAttachment0,
            DrawBuffersEnum.ColorAttachment1,
            DrawBuffersEnum.ColorAttachment2,
            DrawBuffersEnum.ColorAttachment3
        }
        GL.DrawBuffers(4, drawbuffers)
        'GL.DrawBuffer(DrawBufferMode.Back)
        GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)
        GL.Enable(EnableCap.DepthTest)
        GL.ClearColor(0.5, 0.5, 0.5, 0.0)
    End Sub


    Public Sub EndDraw()
        GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0)
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0)
    End Sub
End Class
